package gui;
//Code from: http://www.orbital-computer.de/JComboBox/
/*
Inside JComboBox: adding automatic completion

Author: Thomas Bierhance
        thomas@orbital-computer.de
*/

/*
Ignore input that does not match

If the user entered a key that does not match any item you get a NullPointerException.
Of course this is not acceptable. A small enhancement in the insertString method will
ignore 'invalid' input.
*/

import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.PlainDocument;

public class SameAutoComplete extends PlainDocument {
    SameComboBox comboBox;
    ComboBoxModel model;
    JTextComponent editor;
    // flag to indicate if setSelectedItem has been called
    // subsequent calls to remove/insertString should be ignored
    boolean selecting = false;

    public SameAutoComplete(final SameComboBox comboBox) {
        this.comboBox = comboBox;
        model = comboBox.getModel();
        editor = (JTextComponent) comboBox.getEditor().getEditorComponent();
        try {
            if (comboBox.getSelectedIndex() >= 0) {
                comboBox.setSelectedIndex(-1);
                comboBox.setSelectedIndex(0);
                Object item = comboBox.getSelectedItem();
                if (item != null) {
                    setText(item.toString());
                    comboBox.setToolTipText(comboBox.getToolTip(item));
                }
            }
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    public void remove(int offs, int len) throws BadLocationException {
        // return immediately when selecting an item
        if (selecting) return;
        super.remove(offs, len);
    }

    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
        // return immediately when selecting an item
        if (selecting) return;
        // insert the string into the document
        super.insertString(offs, str, a);
        // lookup and select a matching item
        String text = getText(0, getLength());
        if (text.length() > 0 && !text.equals("")) {
            Object item = lookupItem(text);
            if (item != null) {
                setSelectedItem(item);
                String textTooltip = comboBox.getToolTip(item);
                comboBox.setToolTipText(textTooltip);
            } else {
                // keep old item selected if there is no match
                item = comboBox.getSelectedItem();
                // imitate no insert (later on offs will be incremented by str.length(): selection won't move forward)
                offs = offs - str.length();
                // provide feedback to the user that his input has been received but can not be accepted
                //comboBox.getToolkit().beep(); // when available use: UIManager.getLookAndFeel().provideErrorFeedback(comboBox);
            }
            setText(item.toString());
            // select the completed part
            highlightCompletedText(offs + str.length());
            JTextField tf = (JTextField) comboBox.getEditor().getEditorComponent();
            tf.setCaretPosition(0);
        }
    }

    private void setText(String text) throws BadLocationException {
        // remove all text and insert the completed string
        super.remove(0, getLength());
        super.insertString(0, text, null);
    }

    private void highlightCompletedText(int start) {
        editor.setSelectionStart(start);
        editor.setSelectionEnd(getLength());
    }

    private void setSelectedItem(Object item) {
        selecting = true;
        model.setSelectedItem(item);
        selecting = false;
    }

    private Object lookupItem(String pattern) {
        Object selectedItem = model.getSelectedItem();
        // only search for a different item if the currently selected does not match
        if (selectedItem != null && startsWithIgnoreCase(selectedItem.toString(), pattern)) {
            return selectedItem;
        } else {
            // iterate over all items
            for (int i = 0, n = model.getSize(); i < n; i++) {
                Object currentItem = model.getElementAt(i);
                // current item starts with the pattern?
                if (startsWithIgnoreCase(currentItem.toString(), pattern)) {
                    return currentItem;
                }
            }
        }
        // no item starts with the pattern => return null
        //System.out.println("No item matches pattern '" + pattern + "'");
        return null;
    }

    // checks if str1 starts with str2 - ignores case
    private static boolean startsWithIgnoreCase(String str1, String str2) {
        return str1.toUpperCase().startsWith(str2.toUpperCase());
    }

}